<?php

class T4SecurityLite
{

# --  Cookie configuration --

/**
 * Session cookie name
 * @var string
 */
protected $sSessionCookieName="seed";
/**
 * Session cookie lifetime (in seconds)
 * @var integer
 */
protected $nSessionCookieLife=31536000; // 60*60*24*365
/**
 * Session cookie path
 * @var string
 */
protected $sSessionCookieBase="/";

# -- User system configuration --

/**
 * Availible user ranks
 * @var array[int]string
 */
protected $aUserRanks = array("guest","user","admin","developer");
protected $sNewUserRank = "user";
/**
 * Guest user details ( id, login, rank )
 * @var array[string]mixed
 */
protected $aGuestUser = array("id"=>-1,"login"=>"guest","rank"=>"guest");

# -- Database configuration --

/**
 * Security database filename
 * @var string
 */
protected $sDBFile;
/**
 * Security database handler
 * @var SQLiteDatabase
 */
protected $SQLite;
/**
 * Get (and init) security database
 * @return SQLiteDatabase Security databse handler
 */
protected function DB()
	{
	if(!isset($this->SQLite))
		$this->SQLite = new SQLiteDatabase($this->sDBFile);
	// TODO: ERROR: open/create security database failed
	return $this->SQLite;
	}
	
/**
 * Constructor
 */
public function __construct()
	{
	// Configure database parameters
	if(defined("X4_ENGINEDATA_DIR"))
		$sDBDir = X4_ENGINEDATA_DIR;
	else
		{
		$aPath = pathinfo(__FILE__);
		$sDBDir =  $aPath['dirname'];
		}
	$this->sDBFile = $sDBDir."/security.db";
	
	// Session engine configuration
	if(isset($this->sSessionCookieName)) ini_set('session.name',$this->sSessionCookieName);
	session_set_cookie_params($this->nSessionCookieLife,$this->sSessionCookieBase);
	}
	
/**
 * Setup security
 * * Create accounts table in database
 */
public function Install()
	{
	$this->DB()->queryExec("CREATE TABLE accounts (id,login,password,rank)");
	// TODO: ERROR: Table creating failed
	}

/**
 * Varify username and password
 *
 * @param string $sLogin
 * @param string $sPassword
 * @return array[string]mixed User account
 */
protected function CheckUser($sLogin,$sPassword)
	{
	// Developer built-in account
	if($sLogin=="dev" and defined("X4_DEV_PASSWORD") and md5($sPassword)==X4_DEV_PASSWORD)
		return array("login"=>"dev","id"=>-101,"rank"=>"developer");
	// General account
	$sLogin = sqlite_escape_string($sLogin);
	$res = $this->DB()->query("SELECT * FROM accounts WHERE login='{$sLogin}'",SQLITE_ASSOC);
	if(!$res) return false; // ERROR: Security database connection failed
	$Account = sqlite_fetch_array($res);
	// TODO: FIXME: Fetch
	if(!$Account) return false; // WARNING: No such user
	if(md5($sPassword)!=$Account['password']) return false; // WARNING: Incorrect password
	unset($Account['password']);
	return $Account;
	}

/**
 * Log user in and (if succeedes) starts session
 *
 * @param string $sLogin
 * @param string $sPassword
 * @return integer User id or false if Login failed
 */
public function Login($sLogin,$sPassword)
	{
	if($Account = $this->CheckUser($sLogin,$sPassword))
		{
		$this->Logoff();
		session_start();
		$_SESSION['user'] = $Account;
		return $Account['id'];
		}
	else
		return false;
	}
	
/**
 * Terminates user session
 */
public function Logoff()
	{
	setcookie($this->sSessionCookieName,"",-4400);
	$_SESSION = array();
	if(session_id())session_destroy();
	return true;
	}
	
/**
 * Read current user
 */
public function Authenticate()
	{
	if(!session_id()) session_start();
	if(!isset($_SESSION['user'])) $_SESSION['user'] = $this->aGuestUser;	
	}
	
/**
 * Get Current User
 * @return array[string]mixed User details structure
 */
public function getCurrentUser()
	{
	$this->Authenticate();
	return $_SESSION['user'];
	}
	
/**
 * Adds new user
 *
 * @param string $sLogin
 * @param string $sPassword
 * @return bool Succeeds or failed
 */
public function Register($sLogin,$sPassword)
	{
	// Check login availibility
	if(!$this->CheckLoginFree($sLogin)) return false;
	
	$sLogin = sqlite_escape_string($sLogin);
	$sPasswordHash = md5($sPassword);
	$bCheck = $this->DB()->queryExec("INSERT INTO accounts (login,password,rank) VALUES ({$sLogin},{$sPasswordHash},{$this->sNewUserRank})");
	return $bCheck;
	}
	
/**
 * Check wether login free or not
 *
 * @param string $sLogin
 * @return bool
 */
public function CheckLoginFree($sLogin)
	{
	// Reserved logins
	if($sLogin==$this->aGuestUser['login'] or $sLogin=="dev") return false;
	
	$sLogin = sqlite_escape_string($sLogin);
	$res = $this->DB()->query("SELECT COUNT(*) FROM accounts WHERE login = {$sLogin}");
	if(!$res) return false; // ERROR: Security database connection failed
	
	$LoginUsed = intval(sqlite_fetch_single($res));
	return ($LoginUsed==0);
	}

/**
 * Check if current user has required access level
 * @param mixed $mLevel Requested access level string or integer
 * @return boolean
 */
public function CheckAccessLevel($mLevel)
	{
	if(is_string($mLevel)) $mLevel = array_search($mLevel,$this->aUserRanks);
	if($mLevel===false) return false; // ERROR: Non-existing level requested
	if(!is_int($mLevel)) return false; // ERROR: Wrong requested level format
	$aCurrentUser = $this->getCurrentUser();
	$iUserLevel = array_search($aCurrentUser['rank'],$this->aUserRanks);
	return ($iUserLevel >= $mLevel);
	}	
}
?>